package com.qqt.csr.route.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrPool;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qqt.csr.common.exception.StatusCode;
import com.qqt.csr.common.utils.CacheKeyUtil;
import com.qqt.csr.common.utils.JsonUtil;
import com.qqt.csr.common.utils.ServiceAssert;
import com.qqt.csr.common.vo.req.PageRequest;
import com.qqt.csr.common.vo.resp.PageResponse;
import com.qqt.csr.route.entity.ServiceTime;
import com.qqt.csr.route.mapper.ServiceTimeMapper;
import com.qqt.csr.route.vo.req.*;
import com.qqt.csr.route.vo.resp.HolidayTimeRespVO;
import com.qqt.csr.route.vo.resp.ServiceTimeInfoRespVO;
import com.qqt.csr.route.vo.resp.WorkOvertimeRespVO;
import com.qqt.csr.route.vo.resp.WorkTimeRespO;
import com.qqt.csr.workbench.vo.resp.SkillSetMemberInfoRespVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ServiceTimeService extends ServiceImpl<ServiceTimeMapper, ServiceTime> {
    @Autowired
    private RedissonClient redissonClient;

    /**
     * 获取服务时间列表
     *
     * @param tenantId
     * @return
     */
    public List<ServiceTime> getServiceTimeList(String tenantId) {
        if (StringUtils.isBlank(tenantId)) {
            return null;
        }

        String cacheKey = String.format(CacheKeyUtil.System.SERVICE_TIME, tenantId);
        return Optional.ofNullable(redissonClient.getBucket(cacheKey).get())
                .map(Object::toString)
                .map(json -> JsonUtil.toList(json, ServiceTime.class))
                .orElseGet(() -> {
                    List<ServiceTime> serviceTimeList = this.lambdaQuery().select().eq(ServiceTime::getTenantId, tenantId).list();
                    redissonClient.getBucket(cacheKey).set(JsonUtil.toJson(serviceTimeList), Duration.of(CacheKeyUtil.EXPIRE_TIME_8H, ChronoUnit.MILLIS));
                    return serviceTimeList;
                });

    }

    /**
     * 根据租户id和服务时间id查询服务时间
     *
     * @param tenantId
     * @param serviceTimeId
     * @return
     */
    public ServiceTime getOneBy(String tenantId, Integer serviceTimeId) {
        return getServiceTimeList(tenantId).stream()
                .filter(item -> item.getId().equals(serviceTimeId))
                .findFirst().orElse(null);
    }

    /**
     * 判断是否命中工作或加班时间
     *
     * @param date
     * @return
     */
    public boolean match(String tenantId, Integer serviceTimeId, Date date) {
        ServiceTime serviceTime = getOneBy(tenantId, serviceTimeId);
        if (serviceTime == null) {
            return false;
        }
        return serviceTime.isWorkTime(date);
    }

    /**
     * 添加服务时间组
     *
     * @param tenantId
     * @param creatorId
     * @param req
     * @return
     */
    public Integer add(String tenantId, Long creatorId, AddingServiceTimeReqVO req) {
        ServiceAssert.isTrue(CollectionUtils.isNotEmpty(req.getWorkTimeList())
                || CollectionUtils.isNotEmpty(req.getWorkOvertimeList())
                || CollectionUtils.isNotEmpty(req.getHolidayList()), StatusCode.Common.NULL_ERROR.getCode(), "请至少添加一种服务时间");

        ServiceTime sameServiceTimeOfName = getServiceTimeList(tenantId)
                .stream().filter(st -> st.getName().equalsIgnoreCase(req.getName()))
                .findFirst().orElse(null);
        ServiceAssert.isTrue(sameServiceTimeOfName == null, StatusCode.Common.UNIQUE_ERROR.getCode(), "已存在相同名称的服务时间组");

        ServiceTime saveServiceTime = new ServiceTime();
        saveServiceTime.setTenantId(tenantId);
        saveServiceTime.setCreatorId(creatorId);
        saveServiceTime.setName(req.getName());

        if (CollectionUtils.isNotEmpty(req.getWorkTimeList())) {
            // 以 | 分组，示例：1-2-3-4-5-6-7 09:12:21_09:13:21
            List<String> workTimeList = new ArrayList<>();
            for (WorkTimeReqVO workTimeReqVO : req.getWorkTimeList()) {
                ServiceAssert.isTrue(workTimeReqVO.getStartTime().compareTo(workTimeReqVO.getEndTime()) < 1, StatusCode.Common.ILLEGAL.getCode(), "工作时间的开始时间段不能大于结束时间段");
                workTimeReqVO.getWeeks().sort(Integer::compareTo);
                String weekStr = StringUtils.join(workTimeReqVO.getWeeks(), StrPool.DASHED);
                workTimeList.add(weekStr + StrPool.C_SPACE + workTimeReqVO.getStartTime() + StrPool.UNDERLINE + workTimeReqVO.getEndTime());
            }
            saveServiceTime.setWorkTime(StringUtils.join(workTimeList, StringPool.PIPE));
        }

        if (CollectionUtils.isNotEmpty(req.getWorkOvertimeList())) {
            // 以 | 分组，示例：2025-01-20 09:12:21_2025-01-20 09:12:21
            List<String> workOvertimeList = new ArrayList<>();
            for (WorkOvertimeReqVO workOvertimeReqVO : req.getWorkOvertimeList()) {
                ServiceAssert.isTrue(workOvertimeReqVO.getStartTime().compareTo(workOvertimeReqVO.getEndTime()) < 1, StatusCode.Common.ILLEGAL.getCode(), "非常规工作时间的开始时间段不能大于结束时间段");
                workOvertimeList.add(DateUtil.formatDateTime(workOvertimeReqVO.getStartTime()) + StrPool.UNDERLINE + DateUtil.formatDateTime(workOvertimeReqVO.getEndTime()));
            }
            saveServiceTime.setWorkOvertime(StringUtils.join(workOvertimeList, StringPool.PIPE));
        }

        if (CollectionUtils.isNotEmpty(req.getHolidayList())) {
            // 以 | 分组，示例：2025-01-20 09:12:21_2025-01-20 09:12:21
            List<String> holidayList = new ArrayList<>();
            for (HolidayTimeReqVO holidayTimeReqVO : req.getHolidayList()) {
                ServiceAssert.isTrue(holidayTimeReqVO.getStartTime().compareTo(holidayTimeReqVO.getEndTime()) < 1, StatusCode.Common.ILLEGAL.getCode(), "节假日时间段的开始时间段不能大于结束时间段");
                holidayList.add(DateUtil.formatDateTime(holidayTimeReqVO.getStartTime()) + StrPool.UNDERLINE + DateUtil.formatDateTime(holidayTimeReqVO.getEndTime()));
            }
            saveServiceTime.setHoliday(StringUtils.join(holidayList, StringPool.PIPE));
        }

        this.save(saveServiceTime);
        return saveServiceTime.getId();
    }

    /**
     * 编辑服务时间组
     * @param tenantId
     * @param req
     */
    public void updateBy(String tenantId, UpdatingServiceTimeReqVO req) {
        ServiceAssert.isTrue(CollectionUtils.isNotEmpty(req.getWorkTimeList())
                || CollectionUtils.isNotEmpty(req.getWorkOvertimeList())
                || CollectionUtils.isNotEmpty(req.getHolidayList()), StatusCode.Common.NULL_ERROR.getCode(), "请至少添加一种服务时间");

        ServiceTime serviceTime = getOneBy(tenantId, req.getId());
        ServiceAssert.notNull(serviceTime, StatusCode.Common.NULL_ERROR.getCode(), "服务时间组不存在");

        ServiceTime updateServiceTime = new ServiceTime();
        updateServiceTime.setId(req.getId());

        if (CollectionUtils.isNotEmpty(req.getWorkTimeList())) {
            // 以 | 分组，示例：1-2-3-4-5-6-7 09:12:21_09:13:21
            List<String> workTimeList = new ArrayList<>();
            for (WorkTimeReqVO workTimeReqVO : req.getWorkTimeList()) {
                ServiceAssert.isTrue(workTimeReqVO.getStartTime().compareTo(workTimeReqVO.getEndTime()) < 1, StatusCode.Common.ILLEGAL.getCode(), "工作时间的开始时间段不能大于结束时间段");
                workTimeReqVO.getWeeks().sort(Integer::compareTo);
                String weekStr = StringUtils.join(workTimeReqVO.getWeeks(), StrPool.DASHED);
                workTimeList.add(weekStr + StrPool.C_SPACE + workTimeReqVO.getStartTime() + StrPool.UNDERLINE + workTimeReqVO.getEndTime());
            }
            updateServiceTime.setWorkTime(StringUtils.join(workTimeList, StringPool.PIPE));
        }

        if (CollectionUtils.isNotEmpty(req.getWorkOvertimeList())) {
            // 以 | 分组，示例：2025-01-20 09:12:21_2025-01-20 09:12:21
            List<String> workOvertimeList = new ArrayList<>();
            for (WorkOvertimeReqVO workOvertimeReqVO : req.getWorkOvertimeList()) {
                ServiceAssert.isTrue(workOvertimeReqVO.getStartTime().compareTo(workOvertimeReqVO.getEndTime()) < 1, StatusCode.Common.ILLEGAL.getCode(), "非常规工作时间的开始时间段不能大于结束时间段");
                workOvertimeList.add(DateUtil.formatDateTime(workOvertimeReqVO.getStartTime()) + StrPool.UNDERLINE + DateUtil.formatDateTime(workOvertimeReqVO.getEndTime()));
            }
            updateServiceTime.setWorkOvertime(StringUtils.join(workOvertimeList, StringPool.PIPE));
        }

        if (CollectionUtils.isNotEmpty(req.getHolidayList())) {
            // 以 | 分组，示例：2025-01-20 09:12:21_2025-01-20 09:12:21
            List<String> holidayList = new ArrayList<>();
            for (HolidayTimeReqVO holidayTimeReqVO : req.getHolidayList()) {
                ServiceAssert.isTrue(holidayTimeReqVO.getStartTime().compareTo(holidayTimeReqVO.getEndTime()) < 1, StatusCode.Common.ILLEGAL.getCode(), "节假日时间段的开始时间段不能大于结束时间段");
                holidayList.add(DateUtil.formatDateTime(holidayTimeReqVO.getStartTime()) + StrPool.UNDERLINE + DateUtil.formatDateTime(holidayTimeReqVO.getEndTime()));
            }
            updateServiceTime.setHoliday(StringUtils.join(holidayList, StringPool.PIPE));
        }

        this.updateById(updateServiceTime);
        clearCache(tenantId);
    }

    /**
     * 删除服务时间组
     * @param tenantId
     * @param req
     */
    public void delete(String tenantId , DeletingServiceTimeReqVO req) {
        if(CollectionUtils.isEmpty(req.getIdList())){
            return;
        }
        this.lambdaUpdate().set(ServiceTime::getDeleteFlag, 1)
                .set(ServiceTime::getUpdateTime, new Date())
                .in(ServiceTime::getId, req.getIdList())
                .eq(ServiceTime::getTenantId, tenantId)
                .update();
        clearCache(tenantId);
    }

    /**
     * 分页查询服务时间组
     * @param req
     * @return
     */
    public PageResponse<ServiceTimeInfoRespVO> queryPage(PageRequest<QueryingServiceTimeReqVO> req) {
        IPage<ServiceTime> page = baseMapper.page(new Page<>(req.getPage(), req.getPageSize()), req.getData());

        List<ServiceTimeInfoRespVO> resultList = page.getRecords().stream()
                .map(serviceTime -> {
                    ServiceTimeInfoRespVO serviceTimeInfoRespVO = ServiceTimeInfoRespVO.builder()
                            .id(serviceTime.getId())
                            .name(serviceTime.getName())
                            .build();

                    List<WorkTimeRespO> workTimeList = new ArrayList<>();
                    if (StringUtils.isNotBlank(serviceTime.getWorkTime())) {
                        String[] weekTimeArray = StringUtils.split(serviceTime.getWorkTime(), StringPool.PIPE);
                        for (String weekTimeStr : weekTimeArray) {
                            //1-2-3-4-5-6-7 09:12:21_09:13:21
                            String[] weekTime = weekTimeStr.split(StringPool.SPACE);
                            String[] weeks = StringUtils.split(weekTime[0], StrPool.DASHED);
                            String[] times = StringUtils.split(weekTime[1], StrPool.UNDERLINE);
                            workTimeList.add(WorkTimeRespO.builder()
                                    .weeks(Arrays.stream(weeks).map(Integer::parseInt).collect(Collectors.toList()))
                                    .startTime(times[0])
                                    .endTime(times[1])
                                    .build());
                        }
                    }
                    serviceTimeInfoRespVO.setWorkTimeList(workTimeList);

                    List<HolidayTimeRespVO> holidayList = new ArrayList<>();
                    if (StringUtils.isNotBlank(serviceTime.getHoliday())) {
                        String[] holidayTimeArray = StringUtils.split(serviceTime.getHoliday(), StringPool.PIPE);
                        for (String holidayTimeStr : holidayTimeArray) {
                            //2025-01-20 09:12:21_2025-01-20 09:12:21
                            String[] holidayTime = holidayTimeStr.split(StrPool.UNDERLINE);
                            holidayList.add(HolidayTimeRespVO.builder()
                                    .startTime(DateUtil.parseDateTime(holidayTime[0]))
                                    .endTime(DateUtil.parseDateTime(holidayTime[1]))
                                    .build());
                        }
                    }
                    serviceTimeInfoRespVO.setHolidayList(holidayList);

                    List<WorkOvertimeRespVO> workOvertimeList = new ArrayList<>();
                    if (StringUtils.isNotBlank(serviceTime.getWorkOvertime())) {
                        String[] workOvertimeTimeArray = StringUtils.split(serviceTime.getWorkOvertime(), StringPool.PIPE);
                        for (String workOvertimeTimeStr : workOvertimeTimeArray) {
                            //2025-01-20 09:12:21_2025-01-20 09:12:21
                            String[] workOvertimeTime = workOvertimeTimeStr.split(StrPool.UNDERLINE);
                            workOvertimeList.add(WorkOvertimeRespVO.builder()
                                    .startTime(DateUtil.parseDateTime(workOvertimeTime[0]))
                                    .endTime(DateUtil.parseDateTime(workOvertimeTime[1]))
                                    .build());
                        }
                    }
                    serviceTimeInfoRespVO.setWorkOvertimeList(workOvertimeList);

                    return serviceTimeInfoRespVO;
                }).collect(Collectors.toList());

        return new PageResponse<>(page.getTotal(), req.getPageSize(), req.getPage(), resultList);
    }

    /**
     * 清理缓存
     *
     * @param tenantId
     */
    private void clearCache(String tenantId) {
        String cacheKey = String.format(CacheKeyUtil.System.SERVICE_TIME, tenantId);
        redissonClient.getBucket(cacheKey).deleteAsync();
    }



}
